#include "getsection.h"
#include "getpidpackage.h"

GetSection::GetSection()
{

}

GetSection::~GetSection()
{
}

GetSection &GetSection::get_instance()
{
    static GetSection instance;
    return instance;
}

int GetSection::GetTheLoadBeginPostion(unsigned char *pucPackageBuffer)
{
    int iLoadBeginPosition = -1;
    TS_PACKAGE_HEAD stTS_PackageHead = {0};

    GetPidPackage::get_instance().ParseTS_PackageHead(&stTS_PackageHead, pucPackageBuffer);
    switch (stTS_PackageHead.adaption_field_control)
    {
        case 0:
            return -1;
        case 1:
            iLoadBeginPosition = 4;
            break;
        case 2:
            return -1;
        case 3:
            iLoadBeginPosition = 5 + pucPackageBuffer[4];
            break;
    }
    if (stTS_PackageHead.payload_unit_start_indicator)
    {
        iLoadBeginPosition = iLoadBeginPosition + pucPackageBuffer[iLoadBeginPosition] + 1;
    }
    return iLoadBeginPosition;
}

void GetSection::PutTheBufferToSection(unsigned char *pucSectionBuffer, unsigned char *pucPackageBuffer, int *piAlreadyAddSection,
        SECTION_HEAD *pstSectionHead)
{
    int iLoadBeginPosition = 0;
    int iCopyLength = 0;

    iLoadBeginPosition = GetTheLoadBeginPostion(pucPackageBuffer);
    iCopyLength = 188 - iLoadBeginPosition;
    if ((int)(pstSectionHead->section_length + 3) < (188 - iLoadBeginPosition + (*piAlreadyAddSection)))
    {
        iCopyLength = pstSectionHead->section_length + 3 - (*piAlreadyAddSection);
    }
    memcpy(pucSectionBuffer + (*piAlreadyAddSection), pucPackageBuffer + iLoadBeginPosition, iCopyLength);
    (*piAlreadyAddSection) = (*piAlreadyAddSection) + iCopyLength;
}

int GetSection::GetOneSection(FILE *pfTsFile, int iTsLength, unsigned char *pucSectionBuffer, unsigned int uiPID, unsigned int uiTableId, unsigned int *puiVersion)
{
    int iPayloadPosition = -1;
    int iFlagSectionStart = 0;
    int iAlreadyAddSection = 0;
    SECTION_HEAD stSectionHead = {0};
    TS_PACKAGE_HEAD stTS_PackageHead = {0};
    unsigned char aucPackageBuffer[PACKAGE_MAX_LENGTH_204] = {0};

    memset(pucSectionBuffer, 0, sizeof(char) * SECTION_MAX_LENGTH_4096); // initial the section buffer
    while (!feof(pfTsFile))
    {
        if ((sizeof(char) * iTsLength) != (fread((unsigned char *)aucPackageBuffer, sizeof(char), iTsLength, pfTsFile)))
        {
            break;
        }
        GetPidPackage::get_instance().ParseTS_PackageHead(&stTS_PackageHead, aucPackageBuffer);
        if ((stTS_PackageHead.PID == uiPID) && (0x47 == stTS_PackageHead.sync_byte))
        {
            iPayloadPosition = GetTheLoadBeginPostion(aucPackageBuffer);
            if (-1 == iPayloadPosition) // no effective data in the package
            {
                continue;
            }
            if ((stTS_PackageHead.payload_unit_start_indicator == 1) && (aucPackageBuffer[iPayloadPosition] == uiTableId))
            {
                ParseSectionHeader(&stSectionHead, aucPackageBuffer);
                if (1 == IsVersionChange(&stSectionHead, puiVersion))
                {
                    return 0; //version number change again get the table
                }
                iFlagSectionStart = 1;
                PutTheBufferToSection(pucSectionBuffer, aucPackageBuffer, &iAlreadyAddSection, &stSectionHead);
            }
            else
            {
                if (1 == iFlagSectionStart)
                {
                    PutTheBufferToSection(pucSectionBuffer, aucPackageBuffer, &iAlreadyAddSection, &stSectionHead);
                }
            }
        }
        if (1 == iFlagSectionStart)
        {
            if (1 == IsOneSectionOver(stSectionHead, iAlreadyAddSection))
            {
                return 1;
            }
        }
    }
    return -1;
}

int GetSection::GetEIT_OneSection(FILE *pfTsFile, int iTsLength, unsigned char *pucSectionBuffer, unsigned int uiTableId, unsigned uiTableIdExtension, unsigned int *puiVersion)
{
    int iPayloadPosition = -1;
    int iFlagSectionStart = 0;
    int iAlreadyAddSection = 0;
    SECTION_HEAD stSectionHead = {0};
    TS_PACKAGE_HEAD stTS_PackageHead = {0};
    unsigned char aucPackageBuffer[PACKAGE_MAX_LENGTH_204] = {0};

    memset(pucSectionBuffer, 0, sizeof(char) * SECTION_MAX_LENGTH_4096); // initial the section buffer
    while (!feof(pfTsFile))
    {
        if ((sizeof(char) * iTsLength) != (fread((unsigned char *)aucPackageBuffer, sizeof(char), iTsLength, pfTsFile)))
        {
            break;
        }
        GetPidPackage::get_instance().ParseTS_PackageHead(&stTS_PackageHead, aucPackageBuffer);
        if ((stTS_PackageHead.PID == 0x0012) && (0x47 == stTS_PackageHead.sync_byte))
        {
            iPayloadPosition = GetTheLoadBeginPostion(aucPackageBuffer);
            if (-1 == iPayloadPosition) // no effective data in the package
            {
                continue;
            }
            if ((stTS_PackageHead.payload_unit_start_indicator == 1) && (aucPackageBuffer[iPayloadPosition] == uiTableId))
            {
                ParseSectionHeader(&stSectionHead, aucPackageBuffer);

                if (stSectionHead.table_id_extension != uiTableIdExtension) // point the program which we want to know the EIT information
                {
                    continue;
                }

                if (1 == IsVersionChange(&stSectionHead, puiVersion))
                {
                    return 0; //version number change ready for next table
                }
                iFlagSectionStart = 1;
                PutTheBufferToSection(pucSectionBuffer, aucPackageBuffer, &iAlreadyAddSection, &stSectionHead);
            }
            else
            {
                if (1 == iFlagSectionStart)
                {
                    PutTheBufferToSection(pucSectionBuffer, aucPackageBuffer, &iAlreadyAddSection, &stSectionHead);
                }
            }
        }
        if (1 == iFlagSectionStart)
        {
            if (1 == IsOneSectionOver(stSectionHead, iAlreadyAddSection))
            {
                return 1;
            }
        }
    }
    return -1;
}

int GetSection::IsSectionGetBefore(unsigned char *pucSectionBuffer, unsigned int *puiRecordSectionNumber)
{
    int iLoopTime = 1;
    int iLength = (int)puiRecordSectionNumber[0];
    unsigned int uiSectioNumber = pucSectionBuffer[6];

    /*----------------------------------------------------------*/
    /* the first position save the length of the array */
    /*----------------------------------------------------------*/
    for (iLoopTime = 1; iLoopTime < iLength + 1; iLoopTime++)
    {
        if (puiRecordSectionNumber[iLoopTime] == uiSectioNumber)
        {
            return 1;
        }
    }
    puiRecordSectionNumber[iLoopTime] = uiSectioNumber;
    puiRecordSectionNumber[0]++; //the count + 1
    return 0;
}

int GetSection::IsAllSectionOver(unsigned char *pucSectionBuffer, unsigned int *puiRecordSectionNumber)
{
    int iLoopTime = 1;
    int iLength = (int)puiRecordSectionNumber[0];
    unsigned int uiSectioNumber = pucSectionBuffer[6];

    /*----------------------------------------------------------*/
    /* the first position save the length of the array */
    /*----------------------------------------------------------*/
    for (iLoopTime = 1; iLoopTime < iLength + 1; iLoopTime++)
    {
        if (puiRecordSectionNumber[iLoopTime] == uiSectioNumber)
        {
            return 1;
        }
    }
    puiRecordSectionNumber[iLoopTime] = uiSectioNumber;
    puiRecordSectionNumber[0]++; //the count + 1
    return 0;
}

int GetSection::IsOneSectionOver(SECTION_HEAD stSectionHead, int iAddLength)
{
    int iSectionLength = (int)(stSectionHead.section_length + 3);

    if (iAddLength == iSectionLength)
    {
        return 1;
    }
    return 0;
}

int GetSection::IsVersionChange(SECTION_HEAD *pstSectionHead, unsigned int *puiRecordVersion)
{
    /*----------------------------------------------------------*/
    /*if the version is 0xff then record new version */
    /*----------------------------------------------------------*/
    if (INITIAL_VERSION == (*puiRecordVersion))
    {
        (*puiRecordVersion) = pstSectionHead->version_number;
    }
    if ((*puiRecordVersion) != pstSectionHead->version_number)
    {
        return 1;
    }
    return 0;
}
void GetSection::ParseSectionHeader(SECTION_HEAD *pstSectionHead, unsigned char *pucPackageBuffer)
{
    int iPayloadPosition = -1;

    iPayloadPosition = GetTheLoadBeginPostion(pucPackageBuffer);

    pstSectionHead->table_id = pucPackageBuffer[iPayloadPosition];
    pstSectionHead->section_syntax_indicator = pucPackageBuffer[1 + iPayloadPosition] >> 7;
    pstSectionHead->zero = (pucPackageBuffer[1 + iPayloadPosition] >> 6) & 0x1;
    pstSectionHead->reserved_1 = (pucPackageBuffer[1 + iPayloadPosition] >> 4) & 0x3;
    pstSectionHead->section_length = (pucPackageBuffer[1 + iPayloadPosition] & 0xf) << 8 | pucPackageBuffer[2 + iPayloadPosition];
    pstSectionHead->table_id_extension = (pucPackageBuffer[3 + iPayloadPosition] << 8) | pucPackageBuffer[4 + iPayloadPosition];
    pstSectionHead->reserved_2 = pucPackageBuffer[5 + iPayloadPosition] >> 6;
    pstSectionHead->version_number = pucPackageBuffer[5 + iPayloadPosition] >> 1 & 0x1F;
    pstSectionHead->current_next_indicator = (pucPackageBuffer[5 + iPayloadPosition] << 7) >> 7;
    pstSectionHead->section_number = pucPackageBuffer[6 + iPayloadPosition];
    pstSectionHead->last_section_number = pucPackageBuffer[7 + iPayloadPosition];

}
